Skip to content

Add Unicode property escape conversion for Script and Binary properties#34

Closed
lahma wants to merge 1 commit into
adams85:masterfrom
lahma:unicode-property-escapes
Closed

Add Unicode property escape conversion for Script and Binary properties#34
lahma wants to merge 1 commit into
adams85:masterfrom
lahma:unicode-property-escapes

Conversation

@lahma

@lahma lahma commented Mar 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds static Unicode 17.0.0 code point range data for all ECMAScript-recognized Script (\p{Script=Latin}), Script_Extensions (\p{scx=Latn}), and Binary (\p{Alphabetic}) properties
  • Enables full regexp-unicode-property-escapes conversion to .NET Regex, where previously only General Categories were convertible (Script/Binary caused ConversionError)
  • Includes a generator tool (tools/UnicodeDataGenerator) to reproduce the data from Unicode consortium UCD files

Previously, patterns like \p{Script=Latin} or \p{Alphabetic} would pass validation but fail conversion with "Unsupported regular expression", because Acornima had no code point range data for these properties. This change embeds ~14K code point ranges (175 scripts × 2 for sc/scx + 50 binary properties) as static data, following the same ReadOnlySpan<int> pattern used by Tokenizer.Helpers.Generated.cs.

Special-case handling for Any (trivial range), ASCII (trivial range), and Assigned (derived at runtime from .NET's CharUnicodeInfo to match the runtime's Unicode version).

Test plan

  • Acornima builds on all TFMs (net462, netstandard2.0, netstandard2.1, net8.0)
  • Existing Acornima test suite passes with no regressions
  • Validated against Jint's test262 suite: removing regexp-unicode-property-escapes from excluded features results in ~1300 newly passing tests (only Unicode version mismatch tests excluded individually)

🤖 Generated with Claude Code

Previously, Acornima could validate \p{Script=Latin} and \p{Alphabetic}
property names but could not convert them to .NET Regex code point ranges,
causing a ConversionError. Only General Categories (e.g. \p{Lu}) were
convertible.

This adds static Unicode 17.0.0 code point range data for all Script,
Script_Extensions, and Binary properties recognized by ECMAScript, enabling
full regexp-unicode-property-escapes support.

Changes:
- UnicodeProperties.Generated.cs: Static code point range data for 175
  scripts (sc/scx) and 50 binary properties, generated from Unicode 17.0.0
  UCD files
- UnicodeProperties.cs: GetScriptRange, GetScriptExtensionsRange, and
  GetBinaryPropertyRange methods with lazy caching. Special-case handling
  for Any, ASCII, and Assigned
- CodePointRange.cs: Cache fields for script/binary property ranges
- Tokenizer.RegExpParser.Unicode.cs: Wire range lookups into
  ValidateUnicodeProperty, split sc/Script from scx/Script_Extensions
- tools/UnicodeDataGenerator: Generator tool to parse UCD files and produce
  the generated C# source

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@adams85

adams85 commented Mar 28, 2026

Copy link
Copy Markdown
Owner

Oh, some RegExp and Unicode, the two banes of my existence... 😅

Although this could be a nice addition, I'm not really fond of the idea of embedding a big chunk of Unicode data in a core parser library. (This is why only General_Category is supported currently to begin with.) Plus, even with this, there's a lot of further Unicode stuff that's still not covered AFAIK...

I think we need to take a step back here as I'm getting pretty convinced that this JS to .NET regexp conversion logic doesn't really belong in a parser library since it's about execution, not syntax. As a matter of fact, it's primarily for supporting Jint, so probably it'd belong there more (or, at least, in a separate package) if we consider responsibilities.

I feel even more strongly about this when I think about the Unicode sets mode, which is the only main blocker of ES2024+ support now.

Support for legacy Unicode mode (flag u) is quirky and limited but Unicode sets mode (flag v) is pretty much impossible to implement on top of the current .NET Regex engine. This is why I think it's not really worth putting additional significant effort in this approach, which will always be quirky, limited and fragile.

Instead, something like this looks like the way forward:

  1. Porting the proper RegExp parser from acornjs. This would kill two birds with one stone: Acornima could validate and parse flag v regexps and could provide AST for a potential standards-compliant RegExp engine as well. (AI agents can probably help with this task a lot.)
  2. Ripping the JS to .NET regexp conversion logic out of Acornima and placing it in a separate package. (In which I wouldn't mind including big amounts of Unicode data.)
  3. Introducing an extension point (probably a callback) in Acornima that would allow the consumer to provide whatever JS to .NET regexp conversion logic they want to use. (This way the current conversion approach would still be available, but Acornima would only have the ability to validate and parse regexps into ASTs out of the box.)
  4. Implementing a standards-compliant RegExp engine in Jint. (Of course, this is a huge task but in the era of AI agents nothing is impossible. 😉 Until it's done, Jint could, of course, continue using the current limited RegExp execution approach.)

At least, I don't really see another viable way of moving Acornima ahead and implementing Unicode sets in Jint.

I can't make promises but I plan to make progress with steps 1-3 in the coming months because this "flag v" thing has been bugging me for way too long now 😅

@adams85

adams85 commented Mar 28, 2026

Copy link
Copy Markdown
Owner

Just to be clear: I'm not rejecting this PR, it's just on hold until the refactor I outlined above is done.

@lahma

lahma commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the feedback. I created this intentionally as draft as I was investigating how far I could go in fixing. So basically running Jint and Acornima sources together against failing tests.

Porting the proper RegExp parser from acornjs. This would kill two birds with one stone: Acornima could validate and parse flag v regexps and could provide AST for a potential standards-compliant RegExp engine as well. (AI agents can probably help with this task a lot.)

Yes, this kind of porting is exactly suited for AI agents, not a bad idea indeed.

Ripping the JS to .NET regexp conversion logic out of Acornima and placing it in a separate package. (In which I wouldn't mind including big amounts of Unicode data.)

If done, I would vote for something shipped as source package or source generator or similar, trying to keep dependency chain small.

Introducing an extension point (probably a callback) in Acornima that would allow the consumer to provide whatever JS to .NET regexp conversion logic they want to use. (This way the current conversion approach would still be available, but
Acornima would only have the ability to validate and parse regexps into ASTs out of the box.)

Sounds goo to me 👍🏻

Implementing a standards-compliant RegExp engine in Jint. (Of course, this is a huge task but in the era of AI agents nothing is impossible. 😉 Until it's done, Jint could, of course, continue using the current limited RegExp execution approach.)

There's a lot of samples of existing work, so shouldn't be impossible, performance is of course always a concern but maybe could utilize mixed-mode where usually done using .NET libraries and complex cases offload to another parser that might not be that fast (or support pre-compilation).

@lahma

lahma commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

Custom regex engine in the works 😆 sebastienros/jint#2380

@adams85

adams85 commented Apr 3, 2026

Copy link
Copy Markdown
Owner

Wow, that was fast! 😮

Now all we need is a QuickJS bytecode-to-IL converter, and we can finally ditch that unholy hack called RegExp to Regex conversion. 😄

@adams85

adams85 commented Apr 3, 2026

Copy link
Copy Markdown
Owner

Or, even better, Jint could generate IL instead of some custom bytecode to begin with. 🤔

The interpreter might be somewhat trickier that way, however Claude might be able to cobble up an IL interpreter tailored to the problem based on some existing implementations such as the CoreCLR IL interpreter or https://github.com/Ourpalm/ILRuntime.

@lahma

lahma commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

Yes, many possible venues to explore indeed. I'm on mobile now but I think at least v flag parsing was a problem. Need to check where the fix needs to go when back in front of keyboard...

@adams85

adams85 commented Apr 3, 2026

Copy link
Copy Markdown
Owner

As a matter of fact, the set of regexps that can be converted to .NET Regexs so they produce results compliant to the ES spec is pretty small: https://github.com/adams85/acornima/?tab=readme-ov-file#regular-expressions

Roughly, it's basic, case-sensitive, non-Unicode patterns. Beyond that, quirks start to appear.

@lahma

lahma commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator Author

I'm closing this in favor of #36 and #37 , there might still be some insight to extract to issues. But this PR's contents no longer serve a purpose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants